package com.ryan.ohos.extension.nested.component;

import com.ryan.ohos.extension.event.interfaces.ViewGroup;
import com.ryan.ohos.extension.nested.*;
import com.ryan.ohos.extension.nested.ScrollHelper;
import ohos.agp.components.*;
import ohos.app.Context;
import ohos.multimodalinput.event.TouchEvent;

/**
 * 实现了{@link NestedScrollingChild}接口的ListContainer
 */
public class NestedListContainer extends ListContainer
        implements Component.TouchEventListener, ViewGroup,
        NestedScrollingChild, ScrollingView {

    private final ScrollHelper helper;
    private long downTime;
    private boolean giveUp, notGiveUp;

    private int scrollY;
    private int scrollX;

    public NestedListContainer(Context context) {
        this(context, null);
    }

    public NestedListContainer(Context context, AttrSet attrSet) {
        this(context, attrSet, null);
    }

    public NestedListContainer(Context context, AttrSet attrSet, String styleName) {
        super(context, attrSet, styleName);

        helper = new ScrollHelper(this);

        setTouchEventListener(this);
        setCanAcceptScrollListener((component, i, b) -> false);

        // 禁止item长按拖动功能
        setLongClickable(false);

        // todo setReboundEffect(true);
        // todo 重写longclick click
    }

    @Override
    public boolean onTouchEvent(Component component, TouchEvent ev) {
        return helper.onTouchEvent(component, ev);
    }

    // ViewGroup

    @Override
    public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
        helper.requestDisallowInterceptTouchEvent(disallowIntercept);
    }

    @Override
    public boolean onInterceptTouchEvent(TouchEvent ev) {
        return helper.onInterceptTouchEvent(ev);
    }

    @Override
    public boolean dispatchTouchEvent(TouchEvent ev) {
        return helper.dispatchTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(TouchEvent ev) {
        if (ev.getAction() == TouchEvent.PRIMARY_POINT_DOWN) {
            giveUp = false;
            notGiveUp = true;
            downTime = System.currentTimeMillis();
        } else if (ev.getAction() == TouchEvent.POINT_MOVE) {
            if (giveUp) return true;
            if (reachThreshold(ev)) {
                if (notGiveUp && (System.currentTimeMillis() - downTime) > 300) {
                    giveUp = true;
                    return true;
                } else {
                    notGiveUp = false;
                }
            } else {
                if (!giveUp && notGiveUp) return true;
            }
        }
        return helper.onTouchEvent(ev);
    }

    @Override
    public boolean isConsumed() {
        return helper.isConsumed();
    }

    // NestedScrollingChild

    @Override
    public void setNestedScrollingEnabled(boolean enabled) {
        helper.setNestedScrollingEnabled(enabled);
    }

    @Override
    public boolean isNestedScrollingEnabled() {
        return helper.isNestedScrollingEnabled();
    }

    @Override
    public boolean startNestedScroll(int axes, int type) {
        return helper.startNestedScroll(axes, type);
    }

    @Override
    public void stopNestedScroll(int type) {
        helper.stopNestedScroll(type);
    }

    @Override
    public boolean hasNestedScrollingParent(int type) {
        return helper.hasNestedScrollingParent(type);
    }

    @Override
    public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, int[] offsetInWindow, int type, int[] consumed) {
        return helper.dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed,
                offsetInWindow, type, consumed);
    }

    @Override
    public boolean dispatchNestedPreScroll(int dx, int dy, int[] consumed, int[] offsetInWindow, int type) {
        return helper.dispatchNestedPreScroll(dx, dy, consumed, offsetInWindow, type);
    }

    @Override
    public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) {
        return helper.dispatchNestedFling(velocityX, velocityY, consumed);
    }

    @Override
    public boolean dispatchNestedPreFling(float velocityX, float velocityY) {
        return helper.dispatchNestedPreFling(velocityX, velocityY);
    }

    // ScrollingView

    @Override
    public ComponentContainer getContainer() {
        return this;
    }

    @Override
    public int getScrollY() {
        return scrollY;
    }

    @Override
    public int getScrollX() {
        return scrollX;
    }

    @Override
    public int getDirection() {
        return getOrientation() + 1;
    }

    @Override
    public void scrollByInternal(int deltaX, int deltaY) {
        // 需要自行计算scrollX、scrollY，因为有时候getScrollValue函数返回有异常
        if (getDirection() == NestedScrollingHelper.SCROLL_AXIS_VERTICAL) {
            scrollY += deltaY;
            if (scrollY < 0) {
                scrollY = 0;
            }
        } else {
            scrollX += deltaX;
            if (scrollX < 0) {
                scrollX = 0;
            }
        }

        scrollTo(scrollX, scrollY);

        if (scrollY > getScrollValue(AXIS_Y)) {
            scrollY = getScrollValue(AXIS_Y);
        }

        if (scrollX > getScrollValue(AXIS_X)) {
            scrollX = getScrollValue(AXIS_X);
        }
    }

    @Override
    public boolean disallowInterceptWhenMoving() {
        return true;
    }

    private boolean reachThreshold(TouchEvent ev) {
        int deltaX = (int) (helper.getX(ev) - helper.getLastMotionX());
        int deltaY = (int) (helper.getY(ev) - helper.getLastMotionY());

        if (getDirection() == NestedScrollingHelper.SCROLL_AXIS_HORIZONTAL) {
            return Math.abs(deltaX) >= ScrollHelper.TOUCH_SLOP;
        } else {
            return Math.abs(deltaY) >= ScrollHelper.TOUCH_SLOP;
        }
    }
}
